<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  
  <meta name="generator" content="Hugo 0.98.0" />

  
  <meta name="description" content="走在通往幸福的路上">
  

  
  <link rel="apple-touch-icon" sizes="180x180" href="https://blog.v5u.win/apple-touch-icon.png">

  
  <link rel="icon" type="image/png" sizes="32x32" href="https://blog.v5u.win/favicon-32x32.png">

  
  <link rel="icon" type="image/png" sizes="16x16" href="https://blog.v5u.win/favicon-16x16.png">

  
  <link rel="manifest" href="https://blog.v5u.win/site.webmanifest">

  
  <link rel="mask-icon" href="https://blog.v5u.win/safari-pinned-tab.svg" color="">

  <meta name="msapplication-TileColor" content="">

  <meta name="theme-color" content="">

  
  <link rel="stylesheet" href="https://blog.v5u.win/css/bootstrap.min.css" />

  
  <title>Flutter 布局 | 为吾优</title>
  

  <style>
body {
  min-width: 300px;
}

.custom-navbar {
  margin-bottom: 1em;
  height: 60px;
}

.custom-navbar a {
  display: inline-block; 
  padding: 18px 0;
  margin-right: 1em; 
  font-weight: bold; 
}

.custom-navbar a:hover,
.custom-navbar a:focus {
  text-decoration: none; 
}

@media print {
  .custom-navbar {
    display: none;
  }
}

article {
  padding-bottom: 1em;
}

img {
  max-width: 100%;
}


body {
  background-color: #fff;
}



body {
  color: #212529;
}



a {
  color: #007bff;
}



a:hover,
a:focus {
  color: #0056b3;
}



.custom-navbar {
  background-color: #212529;
}



.custom-navbar a {
  color: rgba(255,255,255,.75);
}



.custom-navbar a:hover,
.custom-navbar a:focus {
  color: rgba(255,255,255,1);
}



.container {
  max-width: 800px;
}





</style>
</head>

<body>
  <nav class="custom-navbar">
  <div class="container">
    
    <a href="/">文章</a>
    
    <a href="/tags/">标签</a>
    
    <a href="/about/">关于</a>
    
    <a href="/index.xml">RSS</a>
    
  </div>
</nav>
  
  <div class="container">
    <article>
      <h1>Flutter 布局</h1>
<p>[TOC]</p>
<p>flutter 有三层树结构：Widget、Element、RenderObject</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span><span style="color:#66d9ef">import</span> <span style="color:#e6db74">&#39;package:flutter/material.dart&#39;</span>;
</span></span><span style="display:flex;"><span>main()<span style="color:#f92672">=&gt;</span>runApp(MyApp());
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MyApp</span> <span style="color:#66d9ef">extends</span> StatelessWidget {
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  Widget build(BuildContext context) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> MaterialApp(
</span></span><span style="display:flex;"><span>      title: <span style="color:#e6db74">&#34;app title&#34;</span>,
</span></span><span style="display:flex;"><span>      home: JLHomePage(),
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">JLHomePage</span> <span style="color:#66d9ef">extends</span> StatelessWidget {
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  Widget build(BuildContext context) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> Scaffold(
</span></span><span style="display:flex;"><span>      appBar: AppBar(
</span></span><span style="display:flex;"><span>        title: Text(<span style="color:#e6db74">&#34;基础Widget&#34;</span>),
</span></span><span style="display:flex;"><span>      ),
</span></span><span style="display:flex;"><span>      body: JLHomeContent(),
</span></span><span style="display:flex;"><span>      floatingActionButton: FloatingActionButton(
</span></span><span style="display:flex;"><span>        child: Icon(Icons.add),
</span></span><span style="display:flex;"><span>        onPressed: ()<span style="color:#f92672">=&gt;</span>print(<span style="color:#e6db74">&#34;浮动按钮&#34;</span>),
</span></span><span style="display:flex;"><span>      ),
</span></span><span style="display:flex;"><span>      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">JLHomeContent</span> <span style="color:#66d9ef">extends</span> StatefulWidget {
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  _JLHomeContentState createState() <span style="color:#f92672">=&gt;</span> _JLHomeContentState();
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">_JLHomeContentState</span> <span style="color:#66d9ef">extends</span> State<span style="color:#f92672">&lt;</span>JLHomeContent<span style="color:#f92672">&gt;</span> {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">final</span> imgURL <span style="color:#f92672">=</span>  <span style="color:#e6db74">&#34;https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=116882428,1733900798&amp;fm=26&amp;gp=0.jpg&#34;</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  Widget build(BuildContext context) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> Text(<span style="color:#e6db74">&#34;dd&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ImageExtensionDemo</span> <span style="color:#66d9ef">extends</span> StatelessWidget {
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">//    1. 占位图的问题
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//  2. 图片缓存：flutter默认给图片做缓存，最多1000张，最大100M。
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">const</span> ImageExtensionDemo({
</span></span><span style="display:flex;"><span>    Key key,
</span></span><span style="display:flex;"><span>    <span style="color:#960050;background-color:#1e0010">@</span>required <span style="color:#66d9ef">this</span>.imgURL,
</span></span><span style="display:flex;"><span>  }) <span style="color:#f92672">:</span> <span style="color:#66d9ef">super</span>(key: key);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">String</span> imgURL;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  Widget build(BuildContext context) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> FadeInImage(
</span></span><span style="display:flex;"><span><span style="color:#75715e">//      设置过渡动画时间
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        fadeOutDuration: Duration(milliseconds: <span style="color:#ae81ff">1</span>),
</span></span><span style="display:flex;"><span>        fadeInDuration: Duration(milliseconds: <span style="color:#ae81ff">1</span>),
</span></span><span style="display:flex;"><span>        placeholder: AssetImage(<span style="color:#e6db74">&#34;assets/images/a_dot_ham.png&#34;</span>),
</span></span><span style="display:flex;"><span>        image: NetworkImage(imgURL));
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ButtonExtensionDemo</span> <span style="color:#66d9ef">extends</span> StatelessWidget {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">const</span> ButtonExtensionDemo({
</span></span><span style="display:flex;"><span>    Key key,
</span></span><span style="display:flex;"><span>  }) <span style="color:#f92672">:</span> <span style="color:#66d9ef">super</span>(key: key);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  Widget build(BuildContext context) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> Column(
</span></span><span style="display:flex;"><span>      children: <span style="color:#f92672">&lt;</span>Widget<span style="color:#f92672">&gt;</span>[
</span></span><span style="display:flex;"><span><span style="color:#75715e">//       1. button 上下有一定的间距 padding
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//        2. 默认button有默认的宽高 88*36
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//        3. 去除button的内边距
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ButtonTheme(<span style="color:#75715e">// 处理默认的最小宽高
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>          minWidth: <span style="color:#ae81ff">30</span>,
</span></span><span style="display:flex;"><span>          height: <span style="color:#ae81ff">10</span>,
</span></span><span style="display:flex;"><span>          child: FlatButton(
</span></span><span style="display:flex;"><span><span style="color:#75715e">//            清除内边距
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>              padding: EdgeInsets.all(<span style="color:#ae81ff">0</span>),
</span></span><span style="display:flex;"><span><span style="color:#75715e">//              清除外边距
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>              materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
</span></span><span style="display:flex;"><span>              color: Colors.red,
</span></span><span style="display:flex;"><span>              onPressed: (){},
</span></span><span style="display:flex;"><span>              child: Text(<span style="color:#e6db74">&#34;FaltBtn1&#34;</span>)
</span></span><span style="display:flex;"><span>          ),
</span></span><span style="display:flex;"><span>        ),
</span></span><span style="display:flex;"><span>        FlatButton(
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>          onPressed: (){},
</span></span><span style="display:flex;"><span>          color: Colors.red,
</span></span><span style="display:flex;"><span>          child: Text(<span style="color:#e6db74">&#34;FaltB  tn2&#34;</span>),
</span></span><span style="display:flex;"><span>        ),
</span></span><span style="display:flex;"><span>        SizedBox(height: <span style="color:#ae81ff">10</span>,),<span style="color:#75715e">// 设置间距
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>          Container(
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 给button设置宽高，不能直接给btn设置，需要包裹一层Container，然后用btn填充
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">// double.infinity 代表最大，能填充多大填多大
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            width: <span style="color:#66d9ef">double</span>.infinity,
</span></span><span style="display:flex;"><span>            height: <span style="color:#ae81ff">40</span>,
</span></span><span style="display:flex;"><span>            child: FlatButton(
</span></span><span style="display:flex;"><span>                onPressed: (){},
</span></span><span style="display:flex;"><span>              	color: Colors.blue,
</span></span><span style="display:flex;"><span>                child: Text(<span style="color:#e6db74">&#34;登 录&#34;</span>,
</span></span><span style="display:flex;"><span>                     style: TextStyle(fontSize: <span style="color:#ae81ff">20</span>,color: Colors.white),),
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>            )
</span></span><span style="display:flex;"><span>      ],
</span></span><span style="display:flex;"><span>    );
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">IconExtensionDemo</span> <span style="color:#66d9ef">extends</span> StatelessWidget {
</span></span><span style="display:flex;"><span>  <span style="color:#960050;background-color:#1e0010">@</span>override
</span></span><span style="display:flex;"><span>  Widget build(BuildContext context) {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//Icon 是字体图标
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#75715e">//1. 字体图标是矢量图，放大不会失真
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#75715e">//2. 可以设置颜色
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#75715e">//3. 图标很多是，占据控件更小
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//    return Icon(Icons.pets, size: 300,color: Colors.orange,);
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//    return Icon(IconData(0xe91d,fontFamily: &#39;MaterialIcons&#39;) , size: 300,color: Colors.orange,);
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">//  1. Text 中不能直接使用编码，需要转换 0xe91d-&gt; unicode编码
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">return</span> Text(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\ue91d</span><span style="color:#e6db74">&#34;</span>,style: TextStyle(fontSize: <span style="color:#ae81ff">100</span>,color: Colors.orange,fontFamily: <span style="color:#e6db74">&#39;MaterialIcons&#39;</span>),);
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>	
</span></span></code></pre></div><h2 id="单子布局">单子布局</h2>
<p><strong>Align -&gt; Center，Container，Padding</strong></p>
<p>flutter 中的坐标系为: (0, 0)  是中心点。极值(-1, 1)</p>
<pre tabindex="0"><code>				-1
				|
				|
-1------0-------&gt;1
				|
				|
				↓
				1
</code></pre><p>Container layout</p>
<p>RenderWidget -&gt; RenderObject -&gt;</p>
<p>{constraints 约束</p>
<p>BoxConstraint</p>
<p>minWidth minHeight</p>
<p>maxWidth maxHeight}</p>
<p>子组件在父组件的范围内调整Size 大小，子组件超出会报错超出安全区域。</p>
<p>不同的子组件对于同样的约束，表现可能不同。</p>
<h2 id="多子布局">多子布局</h2>
<p>Row Column Stack</p>
<p>Row和Column都是继承自Flex组件,类似CSS中的Flex布局</p>
<h2 id="row的特点水平方向尽可能大的占领空间水平方向也是希望包裹内容">Row的特点：水平方向尽可能大的占领空间，水平方向也是希望包裹内容，</h2>
<p>垂直方向包裹内容。</p>
<pre tabindex="0"><code> /*
    * Flex(direction: Axis.horizontal); = Row
    * Flex(direction: Axis.vertical); = Column
    * 实际开发中不常用Flex
    * */
/*
* MainAxisAlignment:
* - start 主轴开始位置挨个摆放元素
* - end 主轴结束位置挨个摆放元素
* - center 主轴中心位置挨个摆放元素(默认值）
* - spaceBetween  左右两边为0，其他平分间距
* - spaceAround 左右两边间距为其他间距的一半
* - spaceEvenly 所有间距平分
*
* CrossAxisAlignment:
* - start 交叉轴开始位置挨个摆放元素
* - end 交叉轴结束位置挨个摆放元素
* - center 交叉轴中心位置挨个摆放元素(默认值）
* - baseline  基线对齐 CSS，文字排版，四线三格，基线：X下边的线,有文本才有效果
* - stretch 先让交叉轴row占据较大的空间，将所有的子Widget交叉轴的高度，拉升到最大
* */
</code></pre><h2 id="column">Column：</h2>
<p>收缩+拉伸</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span><span style="color:#75715e">/*
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          * 拉伸
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          * Flexible 将屏幕剩余空间集中分配,设置拉伸
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          * - flex:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          * Expended -&gt; Flexible(fit: FlexFit.tight) 通常工程中，用这个更多，很少用Flexible
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          * 空间分配问题：flex 设置了之后，宽度就失效了，之后和flex比例相关了，
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          * 和css不一样，css有一套公式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          * 
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          *
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          * 收缩 也是用Expanded
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          *
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">          * */</span>
</span></span><span style="display:flex;"><span>          Expanded(
</span></span><span style="display:flex;"><span><span style="color:#75715e">//              flex: 1,
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>              child: Container(width: <span style="color:#ae81ff">160</span>,height: <span style="color:#ae81ff">80</span>, color: Colors.red,)
</span></span><span style="display:flex;"><span>          ),
</span></span></code></pre></div><h2 id="stack-层叠组件">Stack 层叠组件</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-dart" data-lang="dart"><span style="display:flex;"><span><span style="color:#75715e">/*
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* Stack 层叠布局组件
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* 根据 alignment: AlignmentDirectional.center, 为原点，按数组顺序叠放
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* 默认大小是包裹内容
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* fit: expand 将子元素拉伸到尽可能大
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* - overflow: 超出部分如何处理 overflow: Overflow.visible,查出部分依然可见，默认不可见
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">*
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* Positioned 定位
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">* */</span>
</span></span><span style="display:flex;"><span>Positioned(
</span></span><span style="display:flex;"><span>              left: <span style="color:#ae81ff">0</span>,
</span></span><span style="display:flex;"><span>              right: <span style="color:#ae81ff">0</span>,
</span></span><span style="display:flex;"><span>              bottom: <span style="color:#ae81ff">0</span>,
</span></span><span style="display:flex;"><span>              child: Container()
</span></span><span style="display:flex;"><span>  )
</span></span></code></pre></div>
    </article>
  </div>

  
  
  

  
</body>

</html>